/********************************************************************************
 * @file    bsp_pwm.c
 * @author  jianqiang.xue
 * @version V2.0.0
 * @date    2023-07-11
 * @brief   改变写法，IO输入
 ********************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include "RTE_Components.h"
#include CMSIS_device_header

#include "bsp_gpio.h"
#include "bsp_pwm.h"
#include "bsp_tim.h"

/* Private Includes ----------------------------------------------------------*/
#include "ls_gpio.h"
#include "ls_syscfg.h"
#if LS_LOG_SWITCH
#include "log.h"
#endif
/* Private define ------------------------------------------------------------*/
#ifndef LS_APP_IO_CHANGE_SUPPORT
#define IO_TYPE(io)  (g_io_cfg[io].type)
#else // 支持可变
#include "app_io.h"
#define IO_TYPE(io)  (g_io_cfg[io].type)
#endif

#define PWM_SEL(TIM, CH, VAL)                                                                                \
    do {                                                                                                     \
        if (VAL == 0xFFFF || VAL > g_tim##TIM##_handle->Init.Period) VAL = g_tim##TIM##_handle->Init.Period; \
        if (g_tim##TIM##_handle->Instance->CCR##CH == VAL) break;                                            \
        HAL_TIM_PWM_Stop(g_tim##TIM##_handle, CH > 1 ? (1 << CH) : 0);                                       \
        g_tim##TIM##_oc_handle->Pulse = VAL;                                                                 \
        HAL_TIM_PWM_ConfigChannel(g_tim##TIM##_handle, g_tim##TIM##_oc_handle, CH > 1 ? (1 << CH) : 0);      \
        HAL_TIM_PWM_Start(g_tim##TIM##_handle, CH > 1 ? (1 << CH) : 0);                                      \
    } while (0);

#define PWM_GET(TIM, CH) g_tim##TIM##_handle->Instance->CCR##CH

/* Private Variables ---------------------------------------------------------*/
static bool g_pwm_init = false;
#if LS_TIM1_EN
extern TIM_HandleTypeDef *g_tim1_handle;
extern TIM_OC_InitTypeDef *g_tim1_oc_handle;
#endif

#if LS_TIM2_EN
extern TIM_HandleTypeDef *g_tim2_handle;
extern TIM_OC_InitTypeDef *g_tim2_oc_handle;
#endif
/* Public function prototypes -----------------------------------------------*/

/**
 * @brief  设置PWM占空比
 * @param  io: 引脚号
 * @param  val: 0-PERIOD PWM值   ls_syscfg.h -- LS_TIMx_PERIOD
 * @retval 0--执行成功  1--IO错误  2--IO类型不支持  3--超出索引
 */
uint8_t bsp_pwm_set_pulse(uint8_t io, uint16_t val) {
    if (io == 0 || (io > LS_IO_NUM - 1)) return 1;
    if (IO_TYPE(io) < IO_TYPE_TIM1_CH1 && IO_TYPE(io) > IO_TYPE_TIM2_CH4)
        return 2;
    switch (IO_TYPE(io) - IO_TYPE_TIM1_CH1) {
#if LS_TIM1_EN
        case BSP_PWM_0:
            PWM_SEL(1, 1, val);
            break;
        case BSP_PWM_1:
            PWM_SEL(1, 2, val);
            break;
        case BSP_PWM_2:
            PWM_SEL(1, 3, val);
            break;
        case BSP_PWM_3:
            PWM_SEL(1, 4, val);
            break;
#endif
#if LS_TIM2_EN
        case BSP_PWM_4:
            PWM_SEL(2, 1, val);
            break;
        case BSP_PWM_5:
            PWM_SEL(2, 2, val);
            break;
        case BSP_PWM_6:
            PWM_SEL(2, 3, val);
            break;
        case BSP_PWM_7:
            PWM_SEL(2, 4, val);
            break;
#endif
        default: return 3;
    }
    return 0;
}

/**
 * @brief 得到定时器计数器值
 * @param  io: 引脚号
 * @retval 得到当前tim cnt值
 */
uint16_t bsp_pwm_get_pulse(uint8_t io) {
    if (io == 0 || (io > LS_IO_NUM - 1))
        return 0;
    if (IO_TYPE(io) < IO_TYPE_TIM1_CH1 && IO_TYPE(io) > IO_TYPE_TIM2_CH4)
        return 0;
    switch (IO_TYPE(io) - IO_TYPE_TIM1_CH1) {
#if LS_TIM1_EN
        case BSP_PWM_0:
            return PWM_GET(1, 1);
        case BSP_PWM_1:
            return PWM_GET(1, 2);
        case BSP_PWM_2:
            return PWM_GET(1, 3);
        case BSP_PWM_3:
            return PWM_GET(1, 4);
#endif
#if LS_TIM2_EN
        case BSP_PWM_4:
            return PWM_GET(2, 1);
        case BSP_PWM_5:
            return PWM_GET(2, 2);
        case BSP_PWM_6:
            return PWM_GET(2, 3);
        case BSP_PWM_7:
            return PWM_GET(2, 4);
#endif
        default: return 0;
    }
    return 0;
}

/**
 * @brief 百分比 转换 装载值
 * @param  io: 引脚号
 * @param  pp: 百分比
 * @retval 装载值
 */
uint16_t bsp_pwm_pp_to_pulse(uint8_t io, uint8_t pp) {
    if (io == 0 || (io > LS_IO_NUM - 1)) return 0;
    if (IO_TYPE(io) < IO_TYPE_TIM1_CH1 && IO_TYPE(io) > IO_TYPE_TIM2_CH4)
        return 0;
    switch (IO_TYPE(io) - IO_TYPE_TIM1_CH1) {
#if LS_TIM1_EN
        case BSP_PWM_0:
            return (uint16_t)(g_tim1_handle->Init.Period * (pp / 100.0));
        case BSP_PWM_1:
            return (uint16_t)(g_tim1_handle->Init.Period * (pp / 100.0));
        case BSP_PWM_2:
            return (uint16_t)(g_tim1_handle->Init.Period * (pp / 100.0));
        case BSP_PWM_3:
            return (uint16_t)(g_tim1_handle->Init.Period * (pp / 100.0));
#endif
#if LS_TIM2_EN
        case BSP_PWM_4:
            return (uint16_t)(g_tim2_handle->Init.Period * (pp / 100.0));
        case BSP_PWM_5:
            return (uint16_t)(g_tim2_handle->Init.Period * (pp / 100.0));
        case BSP_PWM_6:
            return (uint16_t)(g_tim2_handle->Init.Period * (pp / 100.0));
        case BSP_PWM_7:
            return (uint16_t)(g_tim2_handle->Init.Period * (pp / 100.0));
#endif
        default: return 0;
    }
    return 0;
}

/**
 * @brief 得到当前定时器最大装载值
 * @param  io: 引脚号
 * @retval 装载值
 */
uint16_t bsp_pwm_get_max_period(uint8_t io) {
    if (io == 0 || (io > LS_IO_NUM - 1)) return 0;
    if (IO_TYPE(io) < IO_TYPE_TIM1_CH1 && IO_TYPE(io) > IO_TYPE_TIM2_CH4)
        return 0;
    switch (IO_TYPE(io) - IO_TYPE_TIM1_CH1) {
#if LS_TIM1_EN
        case BSP_PWM_0:
            return g_tim1_handle->Instance->ARR;
        case BSP_PWM_1:
            return g_tim1_handle->Instance->ARR;
        case BSP_PWM_2:
            return g_tim1_handle->Instance->ARR;
        case BSP_PWM_3:
            return g_tim1_handle->Instance->ARR;
#endif
#if LS_TIM2_EN
        case BSP_PWM_4:
            return g_tim2_handle->Instance->ARR;
        case BSP_PWM_5:
            return g_tim2_handle->Instance->ARR;
        case BSP_PWM_6:
            return g_tim2_handle->Instance->ARR;
        case BSP_PWM_7:
            return g_tim2_handle->Instance->ARR;
#endif
        default: return 0;
    }
    return 0;
}